const OBJECTS = {
  Image: {
    type: "Image",
    settings: {
      strokeWidth: {
        title: "Width of region borders",
        type: Number,
        param: ($obj, value) => $obj.$controls.forEach(($control) => $control.setAttribute("strokeWidth", value)),
        value: ($obj) => $obj.$controls[0]?.getAttribute("strokeWidth") ?? 1,
      },
      zoom: {
        title: "Allow image zoom (ctrl+wheel)",
        type: Boolean,
        param: "zoom",
      },
      zoomControl: {
        title: "Show controls to zoom in and out",
        type: Boolean,
        param: "zoomControl",
      },
      rotateControl: {
        title: "Show controls to rotate image",
        type: Boolean,
        param: "rotateControl",
      },
    },
  },
  Text: {
    type: "Text",
    settings: {
      granularity: {
        title: "Select text by words",
        type: Boolean,
        param: ($obj, value) =>
          value ? $obj.setAttribute("granularity", "word") : $obj.removeAttribute("granularity"),
        value: ($obj) => $obj.getAttribute("granularity") === "word",
        when: ($obj) => $obj.$controls.filter((c) => c.tagName.endsWith("Labels")).length > 0,
      },
    },
  },
  HyperText: {
    type: "HyperText",
  },
  Audio: {
    type: "Audio",
  },
  AudioPlus: {
    type: "Audio",
  },
  List: {
    type: "List",
  },
  Paragraphs: {
    type: "Paragraphs",
  },
  Table: {
    type: "Table",
  },
  TimeSeries: {
    type: "TimeSeries",
  },
  Video: {
    type: "Video",
  },
};

const Labels = {
  type: "Labels",
  settings: {
    placeLabelsLeft: {
      title: "Display labels:",
      type: ["bottom", "left", "right", "top"],
      control: true,
      when: ($tag) => $tag.$object.tagName !== "Video",
      param: ($control, value) => {
        let $container = $control.parentNode;
        let $labels = $control;

        if ($container.firstChild?.tagName?.toUpperCase() === "FILTER") {
          $labels = $container;
          $container = $labels.parentNode;
        }
        const $obj = $control.$object;
        const inline = ["top", "bottom"].includes(value);
        const reversed = ["top", "left"].includes(value);
        const direction = (inline ? "column" : "row") + (reversed ? "-reverse" : "");
        const alreadyApplied = $container.getAttribute("style")?.includes("flex");

        if (!alreadyApplied) {
          $container = $obj.ownerDocument.createElement("View");
          $labels.parentNode.insertBefore($container, $obj);
          $container.appendChild($obj);
          $container.appendChild($labels);
        }
        $control.setAttribute("showInline", JSON.stringify(inline));
        $container.setAttribute("style", `display:flex;align-items:start;gap:8px;flex-direction:${direction}`);
      },
      value: ($control) => {
        let $container = $control.parentNode;

        if ($container.firstChild?.tagName?.toUpperCase() === "FILTER") {
          $container = $container.parentNode;
        }
        const style = $container.getAttribute("style");
        const direction = style?.match(/direction:(row|column)(-reverse)?/);

        if (!direction) {
          const position = $control.compareDocumentPosition($control.$object);

          return position & Node.DOCUMENT_POSITION_FOLLOWING ? "top" : "bottom";
        }
        if (direction[1] === "column") return direction[2] ? "top" : "bottom";
        return direction[2] ? "left" : "right";
      },
    },
    filter: {
      title: "Add filter for long list of labels",
      type: Boolean,
      control: true,
      param: ($obj, value) => {
        if (value) {
          const $filter = $obj.ownerDocument.createElement("Filter");
          const $container = $obj.ownerDocument.createElement("View");

          $filter.setAttribute("toName", $obj.getAttribute("name"));
          $filter.setAttribute("minlength", 0);
          $filter.setAttribute("name", "filter"); // @todo should be unique
          $obj.parentNode.insertBefore($container, $obj);
          $container.appendChild($filter);
          $container.appendChild($obj);
        } else {
          const $filter = $obj.previousElementSibling;

          if ($filter.tagName.toUpperCase() === "FILTER") {
            const $container = $obj.parentNode;

            $container.parentNode.insertBefore($obj, $container);
            $container.parentNode.removeChild($container);
          }
        }
      },
      value: ($control) => $control.previousElementSibling?.tagName.toUpperCase() === "FILTER",
    },
  },
};

const CONTROLS = {
  Labels,
  RectangleLabels: Labels,
};

const TAGS = { ...OBJECTS, ...CONTROLS };

export { OBJECTS, CONTROLS, TAGS };
